#include "DOTSdkCallback.h"
#include "DOTSdkAPI.h"
#include "md5sum.h"

#include "DevLed.h"
#include "DevWifi.h"
#include "Qrcode.h"
#include "PowerManager.h"
#include "Video.h"
#include "Audio.h"
#include "app_common.h"
#include <unistd.h>
#include "UpgradeRecovery.h"
#include "System.h"
#include "ping.h"
#include "DevSocSub.h"

#include "include/dot_api.h"
#include "include/dot_error.h"


#define  UPGRADE_FILE   "/ramfs/upgrade.bin"
#define  UPGRADE_INFO   "/config/wjaUpgradeUrl"

#ifdef __cplusplus
extern "C" {
#endif

#define MC_LIVE_PREVIEW_MAX_TIME_SEC    (165) //165s + 15s休眠缓冲时间
char static gs_mcLivePreviewState = 0;

//是否获取到二维码
static int g_get_qrcode = 0;
static int g_keeplive = 0;
static int g_register_status = 0;
static char b_dot_reset_success = 0;
static char g_outIp[32] = "";

#define DEV_CONFIG_MODE_TURNOFF 0
#define DEV_CONFIG_MODE_TURNON  1
#define DEV_CONFIG_MODE_AUTO    2

int QRCode_OriData_Handle(char *pdata, int length)
{
	g_get_qrcode = 1;
	QrcodePushData(pdata, length);
}

FILE *fp = NULL;
static size_t writefile_callback(void *ptr, size_t size, size_t nmemb, void *stream)
{
	int len = size * nmemb;
	int written = len;

	if (fp)
	{
		fwrite(ptr, nmemb, size, fp);
		printf("download size[%dkb]", len / 1024);
	}

	return written;
}

int writeUpgradeInfo(const char *upgradeUrl, const char *md5, int fileLenght)
{
#if 0
	FILE *fp = NULL;
	char upgradeInfo[1024] = { 0 };
	fp = fopen(UPGRADE_INFO, "wb");
	if (fp)
	{
		sprintf(upgradeInfo, "%s %s %d", upgradeUrl, md5, fileLenght);
		fwrite(upgradeInfo, 1, strlen(upgradeInfo), fp);
		fclose(fp);
	} 
#else
    UpgradeRecoverySetInfo(upgradeUrl, md5, fileLenght);
    UpgradeRecoverySetState(1);
#endif
	return 0;
}

int MC_get_register_status(void)
{
	return g_register_status;
}

int DOTRegisterSetLock()
{
	PowerSetWakeLock("Register_LOCK");
}

int DOTRegisterSetUnlock()
{
	PowerSetWakeUnLock("Register_LOCK");
}

int DOTSetLivePreviewState(char state)
{
    gs_mcLivePreviewState = state;
    LOGI("live preview state: %d\n", gs_mcLivePreviewState);
    return 0;
}

int DOTCheckIsLivePreview(void)
{
    int bLivePreview = 0;
    static time_t startLivingTime = 0;
    
    if (gs_mcLivePreviewState == 1) 
    {
        bLivePreview = 1;
        if (startLivingTime == 0) {
            startLivingTime = time(NULL);
        } else {
            if (time(NULL) >= startLivingTime + MC_LIVE_PREVIEW_MAX_TIME_SEC) {
                bLivePreview = 0;
                LOGW("live preview more than the limit (%ds) time!\n", MC_LIVE_PREVIEW_MAX_TIME_SEC);
            }
        }
    }
    else
    {
        startLivingTime = 0;
        bLivePreview = 0;
    }

	return bLivePreview;
}

//based settings配置
static int SetBasedSettingConfig(DoT_SetDevConfigCmd_en cmd, void* data)
{
    int ret = DOT_EC_SUCCESS;
    DoT_int32 value = *(DoT_int32*)data;
    switch (cmd)
    { 
    case DOT_CMD_SET_LED_STATUS:
        if (DEV_CONFIG_MODE_TURNOFF == value) {
            //LED灯关闭
            OUTPUT_LOG("turn off led\n");
        } else if (DEV_CONFIG_MODE_TURNON == value) {
            //LED灯打开
            OUTPUT_LOG("turn on led\n");
        }
        break;
    case DOT_CMD_SET_NIGHTVISIGON_MODE:
    {
    
    }
	break;
    case DOT_CMD_SET_FULL_COLOR_STATUS:
        if (DEV_CONFIG_MODE_TURNOFF == value) {
            //全彩关闭
            OUTPUT_LOG("turn off full color vision\n");
        } else if (DEV_CONFIG_MODE_TURNON == value) {
            //全彩打开
            OUTPUT_LOG("turn on full color vision\n");
        } else if (DEV_CONFIG_MODE_AUTO == value) {
            //全彩自动模式
            OUTPUT_LOG("set full color to automatic mode\n");
        }
        break;

    case DOT_CMD_SET_ANTIFLICKER_VALUE:
        //设置防闪烁频率
        OUTPUT_LOG("set anti-flicker to %dHz\n", value);
        break;
    case DOT_CMD_SET_VIDEO_ROTATE_VALUE:
        //设置图像翻转
        OUTPUT_LOG("set video rotate to %d\n", value);
        break;
    case DOT_CMD_SET_VIDEO_QUALITY_STATUS:
        if (DEV_CONFIG_MODE_TURNOFF == value) {
            //高清关闭
            OUTPUT_LOG("turn off high quality\n");
	    Doorbell_video_set_HD(0);
        } else if (DEV_CONFIG_MODE_TURNON == value) {
            //高清打开
            Doorbell_video_set_HD(1);
            OUTPUT_LOG("turn on high quality\n");
        }
        break;
    case DOT_CMD_SET_DEVICE_STATUS:
        //设置摄像头开关状态
        if (DEV_CONFIG_MODE_TURNOFF == value) {
            //摄像头关闭
            OUTPUT_LOG("turn off camera\n");
        } else if (DEV_CONFIG_MODE_TURNON == value) {
            //摄像头打开
            OUTPUT_LOG("turn on camera\n");
        }
        break;
    case DOT_CMD_SET_PIR_STATUS:
        //设置PIR检测开关状态
        break;
    case DOT_CMD_SET_TAMPER_ALARM_STATUS:
    	//设置防拆报警功能开关状态
        if (DEV_CONFIG_MODE_TURNOFF == value) {
            //防拆报警关闭
            OUTPUT_LOG("turn off tamper alarm\n");
        } else if (DEV_CONFIG_MODE_TURNON == value) {
            //防拆报警打开
            OUTPUT_LOG("turn on tamper alarm\n");
        }
        break;
    default:
        ret = DOT_EC_UNSUPPORT;
        break;
    }

    return ret;
}


//配置命令回调函数
int cbSetDevConfig(DoT_SetDevConfigCmd_en cmd, DoT_uint32 channel_id, void* data, void* user_data)
{
	int ret = DOT_EC_SUCCESS;
	DoT_int32 value = *(DoT_int32*)data;
	switch (cmd)
	{ 
	case DOT_CMD_SET_LED_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_LED_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_NIGHTVISIGON_MODE:
	{
		int pMode = 0;
		DevConfigGetIrNightMode(&pMode);		
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_NIGHTVISIGON_MODE, value = %d, pmode = %d\n", __FUNCTION__, __LINE__, cmd, value, pMode);		
		if (pMode != value)
			DevConfigSetIrNightMode(value);
		break;
	}
	case DOT_CMD_SET_ANTIFLICKER_VALUE:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_ANTIFLICKER_VALUE\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_VIDEO_ROTATE_VALUE:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_VIDEO_ROTATE_VALUE\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_VIDEO_QUALITY_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_VIDEO_QUALITY_STATUS, value = %d\n", __FUNCTION__, __LINE__, cmd, value);
		ret = SetBasedSettingConfig(cmd, data);
		break;
	}
	case DOT_CMD_SET_DEVICE_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_DEVICE_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_FULL_COLOR_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_FULL_COLOR_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_MOTION_DETECTION_SENSITIVITY:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_MOTION_DETECTION_SENSITIVITY\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_MOTION_DETECTION_REGION:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_MOTION_DETECTION_REGION\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_SOUND_DETECTION_SENSITIVITY:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_SOUND_DETECTION_SENSITIVITY\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_PIR_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_PIR_STATUS, value =%d\n", __FUNCTION__, __LINE__, cmd, value);
		char pir_switch;
		DevConfigGetPirSwitch(&pir_switch);
		if (pir_switch != value)
			DevConfigSetPirSwitch(value);
		break;
	}
	case DOT_CMD_SET_PIR_SENSITIVITY:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_PIR_SENSITIVITY, value = %d\n", __FUNCTION__, __LINE__, cmd, value);
		break;
	}
	case DOT_CMD_SET_PEOPLE_DETECTION_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_PEOPLE_DETECTION_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_TAMPER_ALARM_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_TAMPER_ALARM_STATUS, value = %d\n", __FUNCTION__, __LINE__, cmd, value);
		char pAlarmSwitch;
		DevConfigGetAlarmSwitch(&pAlarmSwitch);
		if (pAlarmSwitch != value)
			DevConfigSetAlarmSwitch(value);
		break;
	}
	case DOT_CMD_SET_SPEAKER_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_SPEAKER_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	case DOT_CMD_SET_SPEAKER_VOLUME:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_SPEAKER_VOLUME value = %d\n", __FUNCTION__, __LINE__, cmd, value);
		#if 1
		PLAY_VOLUME_CONFIG stPlayVol;
		AudioGetOpsHandle()->get_play_volume(&stPlayVol);
		printf("set play volume, old volume = %d, new volume = %d\n", stPlayVol.talkbackVol, value);
		#if 0
		if (value != stPlayVol.talkbackVol)
		    stPlayVol.talkbackVol = (char)(value);
		#else
		if (value > 80 && value <= 100)
		    stPlayVol.talkbackVol = 70;
		else if (value > 60 && value <= 80)
		    stPlayVol.talkbackVol = 60;
		else if (value > 40 && value <= 60)
		    stPlayVol.talkbackVol = 50;
		else if (value > 20 && value <= 40)
		    stPlayVol.talkbackVol = 40;
		else if (value >= 0 && value <= 20)
		    stPlayVol.talkbackVol = 30;
		else
			stPlayVol.talkbackVol = 60;
		#endif
		AudioGetOpsHandle()->set_play_volume(stPlayVol);
		#else
		PLAY_VOLUME_CONFIG stPlayVol;
		stPlayVol.talkbackVol = 60;
		AudioGetOpsHandle()->set_play_volume(stPlayVol);
		#endif
		break;
	}
	case DOT_CMD_SET_DOORBELL_VOLUME:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_DOORBELL_VOLUME\n", __FUNCTION__, __LINE__, cmd);
		
		break;
	}
	case DOT_CMD_SET_MOTION_TRACKING_STATUS:
	{
		printf("%s line(%d) cmd(%d)=DOT_CMD_SET_MOTION_TRACKING_STATUS\n", __FUNCTION__, __LINE__, cmd);
		break;
	}
	default:
		ret = DOT_EC_UNSUPPORT;
		break;
	}

    return ret;
}

//设备运行信息
int cbGetDevRunningInfo(DoT_GetDevRunningInfo_en info_e, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (info_e)
    {
    case DOT_CMD_GET_WIFI_SIGNAL_QUANLITY:
        printf("%s line(%d) cmd(%d)=DOT_CMD_GET_WIFI_SIGNAL_QUANLITY\n", __FUNCTION__, __LINE__, info_e);
	break;
    case DOT_CMD_GET_BATTERY_INFO:
    {
    	int *value = (int *)data;
	BATTERY_STATUS_S pstBatStatus;
	SocSubGetBatteryStatus(&pstBatStatus);
	if (pstBatStatus.chargingStatus == BAT_CHARGING)
		*value = (DoT_int32)DOT_BATTERY_STATUS_CHARGING;
	else if (pstBatStatus.chargingStatus == BAT_FULL)
		*value = (DoT_int32)DOT_BATTERY_STATUS_FULL;
	else if (pstBatStatus.chargingStatus == BAT_DISCHARGING)
		*value = (DoT_int32)DOT_BATTERY_STATUS_NORMAL;
	else
		*value = (DoT_int32)DOT_BATTERY_STATUS_FULL;
	printf("%s line(%d) cmd(%d)=DOT_CMD_GET_BATTERY_INFO=%d\n", __FUNCTION__, __LINE__, info_e, *value);
        break;
    }
    case DOT_CMD_GET_BATTERY_PERCENT:
    {
    	int *value = (int *)data;
        BATTERY_STATUS_S pstBatStatus;
	SocSubGetBatteryStatus(&pstBatStatus);
	*value = pstBatStatus.capacity;
        printf("%s line(%d) cmd(%d)=DOT_CMD_GET_BATTERY_PERCENT=%d\n", __FUNCTION__, __LINE__, info_e, *value);
        break;
    }
    case DOT_CMD_GET_WIFI_LIST:
    {
        printf("%s line(%d) cmd(%d)=DOT_CMD_GET_WIFI_LIST=%d\n", __FUNCTION__, __LINE__, info_e);
        break;
    }
    case DOT_CMD_GET_CURRENT_WIFI:
    {
        DoT_WifiInfo_st* wifi_data = (DoT_WifiInfo_st*)data;
	WIFI_STATUS_INFO_S pstStatusInfo;
	WifiGetStatus(&pstStatusInfo);

        strcpy(wifi_data->ssid, pstStatusInfo.ssid);
        wifi_data->signal = 5;
        wifi_data->encrypt_mode = DoT_WIFI_MODE_WPA_WPA2;
	
        printf("%s line(%d) cmd(%d)=DOT_CMD_GET_CURRENT_WIFI\n", __FUNCTION__, __LINE__, info_e);
        break;
    }    
    case DOT_CMD_GET_STORAGE_PARTITION:
    {
        DoT_StorageSize_st* storageinfo = (DoT_StorageSize_st*)data;
        
        if (storageinfo) {
	    printf("%s line(%d) cmd(%d)=DOT_CMD_GET_STORAGE_PARTITION\n", __FUNCTION__, __LINE__, info_e);
            OUTPUT_LOG("free size:%lld, total size:%lld\n",storageinfo->free_size, storageinfo->total_size);
        }
        break;
    }
    case DOT_CMD_GET_MEDIA_ATTR:
    {
        DoT_StreamMediaType_st* streammediatype = (DoT_StreamMediaType_st*)data;

        if (streammediatype) {
            streammediatype->main_video_type = DOT_VIDEO_TYPE_H264;
            streammediatype->sub_video_type = DOT_VIDEO_TYPE_END;
            streammediatype->main_audio_type = DOT_AUDIO_TYPE_G711A;
            streammediatype->sub_audio_type = DOT_AUDIO_TYPE_END;
	    printf("%s line(%d) cmd(%d)=DOT_CMD_GET_MEDIA_ATTR\n", __FUNCTION__, __LINE__, info_e);
            OUTPUT_LOG("mainvideo:%d subvideo:%d, mainaudio:%d, subaudio:%d\n", streammediatype->main_video_type,
                streammediatype->sub_video_type, streammediatype->main_audio_type, streammediatype->sub_audio_type);
        }
        break;
    }  
    case DOT_CMD_GET_MAX_RESOLUTION:
    {
        DoT_VideoResolutionInfo_st* resolution = (DoT_VideoResolutionInfo_st*)data;
        resolution->video_width = 1080;
        resolution->video_height = 720;
        break;
    }
    default:
        ret = DOT_EC_UNSUPPORT;
        break;
    }
    
    return ret;
}

//设备控制回调
int cbControlDevCmd(DoT_ControlDevCmd_en cmd, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (cmd)
    {
    case DOT_CMD_CHANGE_WIFI:
    {
    	DoT_WifiInfo_st* wifi_data = (DoT_WifiInfo_st*)data;
    	OUTPUT_LOG("to connect wifi ssid %s, password %s, encrypt %d\n", 
            	wifi_data->ssid, wifi_data->password, wifi_data->encrypt_mode);
	
	if (strlen(wifi_data->password))
	{
	        WifiSetConnect(wifi_data->ssid, wifi_data->password, WIFI_ENCRYPT_WPA_WPA2);
	}
	else
	{
		WifiSetConnect(wifi_data->ssid, wifi_data->password, WIFI_ENCRYPT_OPEN);
	}
	printf("%s line(%d) cmd(%d)=DOT_CMD_CHANGE_WIFI\n", __FUNCTION__, __LINE__, cmd);
        break;
    }
    case DOT_CMD_SYNC_SYSTEM_TIME:
    {
        DoT_uint64 tnow = *(DoT_uint64*)data;
        OUTPUT_LOG("DOT_CMD_SYNC_SYSTEM_TIME to set system time, utc time is %lld(ms)\n", tnow);

        struct timeval tv_set;

        tv_set.tv_sec  = tnow / 1000;//sec
        tv_set.tv_usec = tnow % 1000 * 1000;//usec
        if(settimeofday(&tv_set, NULL) < 0) {
            printf("settimeofday error.\n");
        }
	printf("%s line(%d) cmd(%d)=DOT_CMD_SYNC_SYSTEM_TIME\n", __FUNCTION__, __LINE__, cmd);
        break;
    }
    
    case DOT_CMD_GET_SYSTEM_UTC_TIME:
    {        
        DoT_uint64 *tnow = (DoT_uint64*)data;
        struct timeval tv;  
        gettimeofday(&tv, NULL);        
        *tnow = (DoT_uint64)tv.tv_sec*1000 + tv.tv_usec/1000;
        break;
    }
    case DOT_CMD_REBOOT_DEVICE:
    {
	SystemReboot("yidong DOT_CMD_REBOOT_DEVICE");
	printf("%s line(%d) cmd(%d)=DOT_CMD_REBOOT_DEVICE\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("to reboot\n");
        break;
    }
    case DOT_CMD_FORMAT_LOCAL_STORAGE: 	
    {
	printf("%s line(%d) cmd(%d)=DOT_CMD_FORMAT_LOCAL_STORAGE\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("to format local storage\n");
        break;
    }
    case DOT_CMD_GET_LOGS:
    {
//	strcpy((char*)data, "/mnt/temp/device.log");
	printf("%s line(%d) cmd(%d)=DOT_CMD_GET_LOGS\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("to get logs %s\n", (char*)data);
        break;
    }
    case DOT_CMD_START_DEFENSE_ALARM:
    {
        Dot_Strategy_Action* action = (Dot_Strategy_Action*)data;
        OUTPUT_LOG("action type:%d, spkdur:%d, litmode:%d, litdur:%d, buzdur:%d\n",
                action->type, action->spkdur, 
                action->litmode, action->litdur, action->buzdur);
       
	printf("%s line(%d) cmd(%d)=DOT_CMD_START_DEFENSE_ALARM\n", __FUNCTION__, __LINE__, cmd);
        break;
    }
    case DOT_CMD_STOP_TAMPER_ALARM:
    {
	printf("%s line(%d) cmd(%d)=DOT_CMD_STOP_TAMPER_ALARM\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("stop tamper alarm value is %d\n", *(DoT_int32*)data);
        break;
    } 
    case DOT_CMD_EXPAND_INFO:
    {
        OUTPUT_LOG("recv expand info:%s\n", (char*)data);        
        break;
    }
    default:
    {
	ret = DOT_EC_UNSUPPORT;
        break;
    }
    
    }

    return ret;
}

//音频播放回调
int cbAudioPlayCmd(DoT_AudioPlayCmd_en cmd, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (cmd)
    {
    case DOT_CMD_AUDIO_PLAY_START:
	printf("%s line(%d) cmd(%d)=DOT_CMD_AUDIO_PLAY_START\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("audio play start\n");	
	AudioGetOpsHandle()->talkback_start();
	break;
    case DOT_CMD_AUDIO_PLAY_STOP:
        printf("%s line(%d) cmd(%d)=DOT_CMD_AUDIO_PLAY_STOP\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("audio play stop\n");
	AudioGetOpsHandle()->talkback_stop();
	break;
    case DOT_AUDIO_PLAY_DATA:
    {
        DoT_AudioInfo_st* audiodata = (DoT_AudioInfo_st*)data;
        OUTPUT_LOG("audio data len:%d, encode:%d, sample:%d, sample_bit:%d\n",
                    audiodata->data_size, audiodata->media_type, audiodata->sample_rate, audiodata->sample_bit);
	
	if (audiodata->data_size == 0)
	{
		printf("DOT_AUDIO_PLAY_DATA stopped!\n");
	}
	else
	{
		int i;
		if (audiodata->data_size > 1024)
		{
			for (i = 0; i < audiodata->data_size / 1024; i++)
			{
				AudioGetOpsHandle()->talkback_data((unsigned char*)audiodata->data + i*1024, 1024, AUDIO_TYPE_G711A);
			}

			if (audiodata->data_size % 1024 != 0)
				AudioGetOpsHandle()->talkback_data((unsigned char*)audiodata->data + i*1024, audiodata->data_size - i*1024, AUDIO_TYPE_G711A);
		}
		else
		{
			AudioGetOpsHandle()->talkback_data((unsigned char*)audiodata->data, audiodata->data_size, AUDIO_TYPE_G711A);
		}
	}
        break;
    }
    default:
        ret = DOT_EC_UNSUPPORT;
        break;
    }

    return ret;
}

//PTZ命令回调
int cbPTZControl(DoT_PTZControl_en cmd, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (cmd)
    {
    case DOT_CMD_PTZ_GET_POSITION:
    {
        DoT_PtzSpace_st* ptz_pos = (DoT_PtzSpace_st*)data;
        ptz_pos->pan = 0.5;
        ptz_pos->tilt = 0.5;
        OUTPUT_LOG("ptz get position [%f %f]\n", ptz_pos->pan, ptz_pos->tilt);
        break;
    }
    case DOT_CMD_PTZ_MOVE_TO_POSITION:
    {
        //坐标值表示需要移动的点的绝对位置
        DoT_PtzSpace_st* ptz_pos = (DoT_PtzSpace_st*)data;    
        OUTPUT_LOG("ptz move to position [%f %f]\n", 
            ptz_pos->pan, ptz_pos->tilt);
        break;
    }
    case DOT_CMD_PTZ_GOTO_HOME:
        OUTPUT_LOG("ptz goto home\n");
        break;
    case DOT_CMD_PTZ_MOVE_BY_STEP:
    {
        DoT_PTZMoveDirection_en direction = *(DoT_PTZMoveDirection_en*)data;
        OUTPUT_LOG("ptz move by step, direction:%d\n", direction);
        break;
    }
    case DOT_CMD_PTZ_START_MOVE:
    {
        DoT_PTZMoveDirection_en direction = *(DoT_PTZMoveDirection_en*)data;
        OUTPUT_LOG("start ptz move, direction:%d\n", direction);
        break;
    }
    case DOT_CMD_PTZ_STOP_MOVE:
        OUTPUT_LOG("ptz stop move\n");
        break;
    default:
        ret = DOT_EC_UNSUPPORT;
        break;
    }

    return ret;
}

void *DOTServerUnbindThread(void*args)
{
	SET_THREAD_NAME("DOTServerUnbindThread");
    pthread_detach(pthread_self());

	DoT_Reset();
	b_dot_reset_success = 1;

	pthread_exit(0);
}

//服务状态回调
int cbServerStatus(DoT_ServerStatusMsg_en msg, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (msg)
    {
    case DOT_MSG_PLAY_STATUS:
	printf("%s line(%d) cmd(%d)=DOT_MSG_PLAY_STATUS\n", __FUNCTION__, __LINE__, msg);
        OUTPUT_LOG("play status is %d\n", *(DoT_int32*)data);
	DOTSetLivePreviewState((char)(*(DoT_int32*)data));
        break;
    case DOT_MSG_DEV_INACTIVE:  
        //建议进入休眠，设备收到此回调时，需要结合当前设备的状态判断是否需要进入休眠，
        //比如在升级过程中是不能休眠的
        break;
    case DOT_MSG_STREAM_RATELIMIT_STATUS:
	printf("%s line(%d) cmd(%d)=DOT_MSG_STREAM_RATELIMIT_STATUS\n", __FUNCTION__, __LINE__, msg);
    OUTPUT_LOG("stream rate limit status is %d\n", *(DoT_int32*)data);
    break;
    case DOT_MSG_SERVER_ONLINE:
	printf("%s line(%d) cmd(%d)=DOT_MSG_SERVER_ONLINE\n", __FUNCTION__, __LINE__, msg);
    OUTPUT_LOG("server online\n");
	PowerSetSocSleepTime(1, 15);
	DOTSetOnlineState(1);
	DOTSetWifiConfigRun(0);
	g_register_status = 1;
        break;
    case DOT_MSG_SERVER_OFFLINE:
	printf("%s line(%d) cmd(%d)=DOT_MSG_SERVER_OFFLINE\n", __FUNCTION__, __LINE__, msg);
        OUTPUT_LOG("server offline\n");
	DOTSetOnlineState(0);	
	DOTSetWifiConfigRun(0);
	g_register_status = 2;
        break;
    case DOT_MSG_SERVER_UNBIND:
		printf("UNBOUND!!!\n");
    	printf("%s line(%d) cmd(%d)=DOT_MSG_SERVER_UNBIND\n", __FUNCTION__, __LINE__, msg);
        OUTPUT_LOG("device unbind\n");	
        int WaitCnt = 0;
	    pthread_t DotServerUnbindPid;
		int err = pthread_create(&DotServerUnbindPid, NULL, &DOTServerUnbindThread, NULL);
		if (err != 0) {
			LOGE("pthread_create DOTServerUnbindThread failed!\n");
			return -1;
		}

		while (1)
		{
		    if (b_dot_reset_success || WaitCnt >= 20)
		    {
                break;
		    }
		    
            usleep(50 * 1000);
            WaitCnt++;
		}

        if (!b_dot_reset_success)
            printf("DoT_Reset failed");
            
	    DevConfigSetDefault();
	SocSubSetSystemMode(HI_SYSLINK_SYS_MODE_REBOOT);
	
	PowerSetSocSleepTime(AV_TRUE, 1);
        break;
    default:
        break;
    }

    return ret;
}

//在线升级回调
int cbUpgrade(DoT_UpgradeCmd_en cmd, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    static DoT_uint64 pkg_size = 0;
    static char md5sum[128] = {0};
    static DoT_uint64 total_size = 0;
    switch (cmd)
    {
    case DOT_CMD_UPGRADE_PKG_INFO:
    {
        DoT_UpgradePackageInfo_st* pkg_info = (DoT_UpgradePackageInfo_st*)data;
    	printf("%s line(%d) cmd(%d)=DOT_CMD_UPGRADE_PKG_INFO\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("upgrade package size %lld, md5 %s  url %s\n", pkg_info->pkg_size, pkg_info->md5, pkg_info->url);

	pkg_size = 0;
	memset(md5sum, 0, sizeof(md5sum));
        OUTPUT_LOG("upgrade package size %lld, md5 %s  url %s\n", pkg_info->pkg_size, pkg_info->md5, pkg_info->url);
	total_size = pkg_info->pkg_size;
	strcpy(md5sum, pkg_info->md5);
	writeUpgradeInfo((const char*)pkg_info->url, (const char*)pkg_info->md5, pkg_info->pkg_size);
	remove(UPGRADE_FILE);
	UpgradeInit(pkg_info->pkg_size + 1);
	if (access((char*)UPGRADE_FILE, 0) == -1) {
		fp = fopen((char*)UPGRADE_FILE, "wb");
	}
	
	break;
    }
    case DOT_CMD_UPGRADE_DOWNLOAD:
    {
        DoT_DataInfo_st* pkgdata = (DoT_DataInfo_st*)data;
    	printf("%s line(%d) cmd(%d)=DOT_CMD_UPGRADE_DOWNLOAD\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("package data len %d\n", pkgdata->data_size);
	pkg_size += pkgdata->data_size;
	writefile_callback(pkgdata->data, 1, pkgdata->data_size, (void *)UPGRADE_FILE);
	if (pkg_size != 0 &&  pkg_size == total_size)
	{
		printf("ccinfo->pkg_size %d\n", total_size);
		sync();
		fclose(fp);
		fp = NULL;
	}
	break;
    }
    case DOT_CMD_UPGRADE_DOWNLOAD_FINISH:
    {
	printf("%s line(%d) cmd(%d)=DOT_CMD_UPGRADE_DOWNLOAD_FINISH\n", __FUNCTION__, __LINE__, cmd);
        break;
    }
    case DOT_CMD_UPGRADE_DOWNLOAD_FAIL:
    {
	printf("%s line(%d) cmd(%d)=DOT_CMD_UPGRADE_DOWNLOAD_FAIL\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("package download failed\n");
	if (fp)
	{
		fclose(fp);
	}
	UpgradeRecoveryStart(UPGRADE_STATUS_DOWNLOAD_FAIL);
        break;
    }
    case DOT_CMD_UPGRADE_INSTALL:
    {
	printf("%s line(%d) cmd(%d)=DOT_CMD_UPGRADE_INSTALL\n", __FUNCTION__, __LINE__, cmd);
        OUTPUT_LOG("package install\n");
    	int ret = 0;
	printf("%s line(%d) cmd(%d)=CC_CMD_UPGRADE_EXECUTE, download size = %lld\n", __FUNCTION__, __LINE__, cmd, pkg_size);	
	ret = UpgradeRun(UPGRADE_FILE);	
	UpgradeDeinit();
	UpgradeRecoverySetState(0);
	SystemReboot("yd update success");
        break;
    }
    default:
        break;
    }

    return ret;
}

static void OnBindFailed(DoT_DeviceBindInfo_st* bindInfo)
{
    int error = bindInfo->error_code;
    OUTPUT_LOG("bind failed, error %d\n", error);
    if (DOT_EC_WIFI_CONNECT_ERROR == error) {
        OUTPUT_LOG("connect wifi failed\n");
    } else if (DOT_EC_BIND_INFO_ERROR == error) {
        OUTPUT_LOG("bind info error\n");
    } else if (DOT_EC_TIMEOUT == error) {
        OUTPUT_LOG("bind request timeout\n");
    } else if (DOT_EC_BIND_ID_NOTINITED == error) {
        OUTPUT_LOG("bind id not inited\n");
    } else if (DOT_EC_BIND_ID_USED == error) {
        OUTPUT_LOG("bind id not used\n");
    } else if (DOT_EC_BIND_PASSWORD_WRONG == error) {
        OUTPUT_LOG("bind password wrong\n");
    } else if (DOT_EC_BIND_DEVICE_MODEL_ERROR == error) {
        OUTPUT_LOG("bind device model id invalid\n");
    } else if (DOT_EC_BIND_USER_INFO_ERROR == error) {
        OUTPUT_LOG("bind no user info\n");
    } else if (DOT_EC_BIND_OTHER_FAILURE == error) {
        OUTPUT_LOG("other reason\n");
    }
}

void *DOTWifiConfigThread(void*args)
{
	SET_THREAD_NAME("DOTWifiConfigThread");
    pthread_detach(pthread_self());
	
	time_t start_time = time(NULL);
	static time_t curTime = 0;
	
	while (1)
	{	
		NetLiteosGetAddrInfo("www.baidu.com", g_outIp);
		if (strlen(g_outIp) > 0)
			break;

		if (curTime - start_time >= 15)
		{
			printf("DOTWifiConfigThread NetLiteosGetAddrInfo failed\n");
			break;
		}

		usleep(50* 1000);
	}

	pthread_exit(0);
}

//绑定状态回调
int cbDevBindStatus(DoT_BindStatus_en status, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (status)
    {
    case DOT_DEVICE_BIND_REQUEST_INFO_START:
    {
	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_REQUEST_INFO_START\n", __FUNCTION__, __LINE__, status);
        OUTPUT_LOG("bind request info start\n");
        //启动二维码扫描模块或者AP热点，详情参看头文件注释说明
        break;
    }
    case DOT_DEVICE_BIND_REQUEST_QRCODE_INFO:     ///< 包括结束符最长512字节
    {
    	
	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_REQUEST_QRCODE_INFO\n", __FUNCTION__, __LINE__, status);
        if (1)
		{
			int nDataLen = 0;
			char* pQrcodeData = NULL;
			QrcodePopData(&pQrcodeData, &nDataLen);
			if (pQrcodeData)
			{
				memcpy((char *)data ,pQrcodeData, nDataLen);
			        OUTPUT_LOG("bind request qrcode info %s\n", data);
				free(pQrcodeData);
				pQrcodeData = NULL;
			}
			else
			{
				OUTPUT_LOG("Get QRcode Result:Unidentified !!! =========>\n");
				ret = DOT_EC_NO_QRCODE;  //尚未解析到二维码的时候，返回错误
			}
        }
	else
	{
		static int idx = 0;
		if (idx++ % 5 == 0) {
			OUTPUT_LOG("in bind proc to get qrcode!\n");
		}
		ret = DOT_EC_NO_QRCODE;  //尚未解析到二维码的时候，返回错误
        }
        g_get_qrcode = 0;
        break;
    }
    case DOT_DEVICE_BIND_REQUEST_INFO_STOP:
    {
	 printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_REQUEST_INFO_STOP\n", __FUNCTION__, __LINE__, status);
        OUTPUT_LOG("bind request info stop\n");
        //收到绑定信息，停止二维码扫描模块，或者退出AP热点模式
        break;
    }
    case DOT_DEVICE_BIND_CONNECT_WIFI:
    {
	DOTSetWifiConfigRun(0);
	DOTSetConfigFailParam(0);
  	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_CONNECT_WIFI\n", __FUNCTION__, __LINE__, status);
	while (AudioGetOpsHandle()->play_file_start(AUDIO_RCVWAVE_SUCCESS, AUDIO_TYPE_MP3, 0) < 0)
	{
                usleep(100 * 1000);
    }
	DoT_WifiInfo_st* wifi_data = (DoT_WifiInfo_st*)data;
	OUTPUT_LOG("to connect wifi ssid %s, password %s, encrypt %d\n", 
            	wifi_data->ssid, wifi_data->password, wifi_data->encrypt_mode);

	if (strlen(wifi_data->password)) {
		WifiSetConnect(wifi_data->ssid, wifi_data->password, WIFI_ENCRYPT_WPA_WPA2);
	} else {
		WifiSetConnect(wifi_data->ssid, wifi_data->password, WIFI_ENCRYPT_OPEN);
	}

	//规避配网过程中再次按下配置键
	if (DOTGetWifiConfigRun())
	{
		LOGD("\nwifi config run on DOT_DEVICE_BIND_CONNECT_WIFI\n");
		QrcodeClearData();
		return -1;
	}
	
	if (WifiCheckIsConnected())
	{
		printf("\n\n\nwifi connected\n\n\n\n");
		/* wait wan net ok */
		int ret = 0;
		int WaitCount = 0;

		pthread_t DotWifiConfigPid;
		int err = pthread_create(&DotWifiConfigPid, NULL, &DOTWifiConfigThread, NULL);
		if (err != 0) {
			LOGE("pthread_create MobileCountryThread failed!\n");
			return -1;
		}
		
		while (1) {

			if (strlen(g_outIp) > 0)
			{
				printf("wait wan net ok!!!\n");
				QrcodeScanStop();
				QrcodeClearData();
				return 0;
			}

			if (DOTGetWifiConfigRun())
			{
				LOGD("\nwifi config run on DOT_DEVICE_BIND_CONNECT_WIFI\n");
				QrcodeClearData();
				return -1;
			}

			usleep(100 * 1000);
			WaitCount++;
			if (WaitCount >= 150)
			{ //15s
				printf("wait wan net ok failed!!!\n");
				g_register_status = 1;				
				DOTRegisterSetUnlock();
				PowerSetSocSleepTime(1, 15);
				if (!DOTGetConfigFailParam() && !DOTGetWifiConfigRun())
				{
					while (AudioGetOpsHandle()->play_file_start(AUDIO_CONFIG_FAIL, AUDIO_TYPE_MP3, 0) < 0)
					{
						usleep(100 * 1000);
					}
					DOTSetConfigFailParam(1);
				}
				if (DOTGetWifiConfigRun())
				{
					LOGD("\nwifi config run on DOT_DEVICE_BIND_CONNECT_WIFI\n");
					QrcodeClearData();
					return -1;
				}
				sleep(5);
				QrcodeScanStop();
				QrcodeClearData();
				return -1;
			}
			else
			{
				if (WaitCount % 10 == 0)
					printf("waiting wan net!!!WaitCount = %d\n", WaitCount);
			}
		}
		return 0;
	}
	else
	{
		printf("\n\n\n\ncan not connect wifi\n\n\n\n");
		QrcodeScanStop();
		QrcodeClearData();
		return -1;
	}

        break;
    }
    case DOT_DEVICE_BIND_SUCCEED:
    {
	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_SUCCEED\n", __FUNCTION__, __LINE__, status);
        OUTPUT_LOG("bind succeed, username:%s\n", ((DoT_DeviceBindInfo_st*)data)->username);
	g_register_status = 1;
	while (AudioGetOpsHandle()->play_file_start(AUDIO_CONFIG_SUCCESS, AUDIO_TYPE_MP3, 0) < 0)
	{
        	 usleep(100 * 1000);
    }
    DOTClearEvent();
	DOTMediaClearData();
	DOTRegisterSetUnlock();
	PowerSetSocSleepTime(1, 30);
	DOTSetWifiConfigRun(0);
        break;
    }
    case DOT_DEVICE_BIND_FAILED:
    {
	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_FAILED\n", __FUNCTION__, __LINE__, status);
    OnBindFailed((DoT_DeviceBindInfo_st*)data);
    g_register_status = 2;
	if (!DOTGetConfigFailParam() && !DOTGetWifiConfigRun())
	{
		while (AudioGetOpsHandle()->play_file_start(AUDIO_CONFIG_FAIL, AUDIO_TYPE_MP3, 0) < 0)
		{
			usleep(100 * 1000);
		}
		DOTSetConfigFailParam(1);
		sleep(5);
	}
	if (DOTGetWifiConfigRun())
		DOTStartBind(4);
	PowerSetSocSleepTime(AV_TRUE, 5);
	DOTRegisterSetUnlock();
	DOTSetWifiConfigRun(0);
        break;
    }
    case DOT_DEVICE_BIND_WIRED_CONNECT_STATUS:
    {
	printf("%s line(%d) cmd(%d)=DOT_DEVICE_BIND_WIRED_CONNECT_STATUS\n", __FUNCTION__, __LINE__, status);
        //TODO:
        break;
    }
    default:
        ret = DOT_EC_UNSUPPORT;
        break;
    }

    return ret;
}

//运行状态回调
int cbRunningStatus(DoT_RunningStatus_en status, DoT_uint32 channel_id, void* data, void* user_data)
{
    int ret = DOT_EC_SUCCESS;
    switch (status)
    {
    case DOT_RUNNING_STATUS_TCP_ERROR:
        OUTPUT_LOG("TCP connection error\n");
        break;
    case DOT_RUNNING_STATUS_ASSIGN_ERROR:
        OUTPUT_LOG("assign server error\n");
        break;
    case DOT_RUNNING_STATUS_ASSIGN_NULL:
        OUTPUT_LOG("assign null server\n");
        break;
    case DOT_RUNNING_STATUS_HOST_RESOLVE_ERROR:
        OUTPUT_LOG("host resolve error\n");
        break;
    case DOT_RUNNING_STATUS_CA_ERROR:
        OUTPUT_LOG("ca error\n");
        break;
    case DOT_RUNNING_STATUS_SSL_ERROR:
        OUTPUT_LOG("ssl connection error\n");
        break;
    case DOT_RUNNING_STATUS_HEARTBEAT_ERROR:
        OUTPUT_LOG("heart beat error\n");
        break;
    case DOT_RUNNING_STATUS_READ_TIMEOUT:
        OUTPUT_LOG("receive data timeout\n");
        break;
    case DOT_RUNNING_STATUS_READ_ERROR:
        OUTPUT_LOG("receive data error\n");
        break;
    case DOT_RUNNING_STATUS_WRITE_TIMEOUT:
        OUTPUT_LOG("send data timeout\n");
        break;
    case DOT_RUNNING_STATUS_WRITE_ERROR:
        OUTPUT_LOG("send data error\n");
        break;
    case DOT_RUNNING_STATUS_SYS_TIME_ERROR:
        OUTPUT_LOG("system time error\n");
        break;
    case DOT_RUNNING_STATUS_AUTH_ERROR:
        OUTPUT_LOG("server authentication error\n");
        break;
    case DOT_RUNNING_STATUS_NO_VIDEO:
        OUTPUT_LOG("no video\n");
        break;
    case DOT_RUNNING_STATUS_NO_AUDIO:
        OUTPUT_LOG("no audio\n");
        break;
    case DOT_RUNNING_STATUS_LARGE_FRAME:
        OUTPUT_LOG("frame size out of range\n");
        break;
    case DOT_RUNNING_STATUS_VIDEO_AUDIO_UNSYNC:
        OUTPUT_LOG("video and audio unsync\n");
        break;
    default:
        break;
    }

    return ret;
}

#ifdef __cplusplus
}
#endif
